﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using ExtensionMethods;
using PpSmsSender;

namespace RatatoskService
{
    public partial class RatatoskService : ServiceBase
    {
        private PpSmsSender.DbSmsSender smsSender;
        private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
        private readonly ManualResetEvent _startedEvent = new ManualResetEvent(false);
        private volatile bool shutdownRequested;
        private volatile bool hasStopped = false;
        private DateTime lastReport;

        public RatatoskService()
        {
            InitializeComponent();
        }

        private void ReportCallback(string msg)
        {
            if (lastReport.Date != DateTime.Now.Date)
                Trace.WriteLine("=========== " + DateTime.Now.ToString("yyyy-MM-dd") + " =======================");
            lastReport = DateTime.Now;
            Trace.Write(lastReport.ToString("HH:mm:ss ") + msg);
        }


        private static Type GetPlugin(string dllName, string interfaceName)
        {
            Type phoneNumberType = null;
            string phonedll = dllName;
            if (phonedll != "")
            {
                var binFolder = EnvironmentUtils.BinFolder();
                var a = Assembly.LoadFrom(binFolder + @"\" + phonedll);

                foreach (Type t in a.GetTypes().Where(t => t.GetInterface(interfaceName) != null))
                {
                    try
                    {
                        phoneNumberType = t;
                        break;
                    }
                    catch
                    {
                    }
                }
            }
            return phoneNumberType;
        }

        protected override void OnStart(string[] args)
        {
          
            Type phoneNumberType = GetPlugin("" + ConfigurationManager.AppSettings["phoneNumberPlugIn"], "IPhoneNumber") ?? typeof(PhoneNumber);


            List<string> phonelist = new List<string>();

            string conf = ConfigurationManager.AppSettings["rootDirPrefix"] + ConfigurationManager.AppSettings["modemConfigFile"];
            Thread thread =
                new Thread(() =>
                {
                    try
                    {
                        using (this.smsSender = new DbSmsSender(phoneNumberType, conf, this.ReportCallback))
                        {
                            this._startedEvent.Set();
                            this._shutdownEvent.WaitOne(Timeout.Infinite);
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(ex.Message);
                    }
                    this.hasStopped = true;
                    this.smsSender = null;
                });
            thread.Start();
            Trace.WriteLine("Waiting for startup....");
            var waitResult = this._startedEvent.WaitOne(TimeSpan.FromSeconds(60));


            if (waitResult == false)
            {
                Trace.WriteLine("\r\n\r\nFailed to start");
                Console.Error.WriteLine("Timed out in startup. " + (phonelist.Count == 0 ? "No modems connected" : ""));
                this.shutdownRequested = true;
                this._shutdownEvent.Set();
                Thread.Sleep(3000);
                Environment.Exit(1);
            }
            Trace.WriteLine("\r\n\r\nStartup done.");

        }

        protected override void OnStop()
        {
            Trace.WriteLine("Service stopping.");
            shutdownRequested = true;
            _shutdownEvent.Set();

            while (hasStopped == false || shutdownRequested == false)
                Thread.Sleep(1000);

        }
    }
}
